﻿// 2025/10/13: 首个版本
// 2025/10/14: 颜色修正
// 2025/10/17: 选项排序

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Avalonia.Input;
using Avalonia.Media;
using ASEva;
using ASEva.UIAvalonia;
using ASEva.Utility;

namespace CommonSource
{
    partial class SignalChooser : DialogPanel
    {
        public SignalChooser() // For designer
        {
            InitializeComponent();
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
        }

        public SignalChooser(String originSignalID, double? originSignalScale, String unit, String iconResourceName = null)
        {
            InitializeComponent();
            SetResizableMode(300, 300, 440, 600);
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
            Icon = ResourceLoader.Load(iconResourceName)?.ToAvaloniaWindowIcon();
            Title = language["title"];
            model = new SignalChooserViewModel(this, language, originSignalID, originSignalScale, unit);
            DataContext = model;
            initializeTree();
        }

        private async void initializeTree()
        {
            model.Initialize(await AgencyAsync.GetSignalTree());
        }

        private void TreeViewItem_PointerPressed(object sender, PointerPressedEventArgs e)
        {
            if (e.ClickCount == 2) model.Select();
        }

        public SignalConfig SelectedSignal => model.Result;

        private LanguageSwitch language;
        private SignalChooserViewModel model;
    }

    partial class SignalChooserViewModel(DialogPanel owner, LanguageSwitch language, String originSignalID, double? originSignalScale, String unit) : ObservableObject
    {
        public enum TextColor
        {
            Default = 0,
            Green,
            Blue,
            Gray,
        }

        public partial class Node(String key, String _title, bool canBeTarget) : ObservableObject
        {
            public String Key { get; set; } = key;
            public bool CanBeTarget { get; set; } = canBeTarget;

            [ObservableProperty]
            private String title = _title;

            [ObservableProperty]
            [NotifyPropertyChangedFor(nameof(Foreground))]
            private TextColor textColor = TextColor.Default;

            public IBrush Foreground => TextColor switch
            {
                TextColor.Green => App.DarkTheme ? Brushes.PaleGreen : Brushes.DarkGreen,
                TextColor.Blue => App.DarkTheme ? Brushes.SkyBlue : Brushes.DarkBlue,
                TextColor.Gray => Brushes.Gray,
                _ => App.DarkTheme ? Brushes.LightGray : Brushes.Black,
            };

            [ObservableProperty]
            private bool isExpanded = false;

            [ObservableProperty]
            private ObservableCollection<Node> subNodes = new();
        }

        [ObservableProperty]
        private bool canSearch = false;

        [ObservableProperty]
        private String searchText = "";

        [ObservableProperty]
        private ObservableCollection<Node> treeNodes = new();

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanSelect))]
        private Node selectedTreeNode = null;

        public bool ShowScaleControls => originSignalScale != null;

        public bool ShowUnit => !String.IsNullOrEmpty(unit);

        public bool ShowDeleteButton => originSignalID != null;

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(ScaleForeground))]
        [NotifyPropertyChangedFor(nameof(CanSelect))]
        private String scaleText = originSignalScale?.ToString();

        private bool scaleValid
        {
            get
            {
                if (String.IsNullOrEmpty(ScaleText)) return false;
                else if (Double.TryParse(ScaleText, out var val)) return val != 0;
                else return false;
            }
        }

        public IBrush ScaleForeground => scaleValid ? (App.DarkTheme ? Brushes.PaleGreen : Brushes.DarkGreen) : (App.DarkTheme ? Brushes.Tomato : Brushes.Red);

        public String Unit => unit;

        public bool CanSelect => SelectedTreeNode != null && SelectedTreeNode.CanBeTarget && (originSignalScale == null || scaleValid);

        public String ResultSignalID { get; set; } = originSignalID == null ? null : originSignalID;
        public double? ResultScale { get; set; } = originSignalScale == null ? null : originSignalScale;

        public SignalConfig Result => ResultSignalID == null ? null : new SignalConfig
        {
            SignalID = ResultSignalID,
            Scale = ResultScale,
        };

        [RelayCommand]
        public void Select()
        {
            if (!CanSelect) return;
            ResultSignalID = SelectedTreeNode.Key;
            ResultScale = scaleValid ? Convert.ToDouble(ScaleText) : null;
            owner.Close();
        }

        [RelayCommand]
        public void Delete()
        {
            ResultSignalID = null;
            ResultScale = null;
            owner.Close();
        }

        public void Initialize(SignalTreeNode[] fullTree)
        {
            this.fullTree = fullTree;
            if (fullTree != null && updateTreeNodes(true)) CanSearch = true;
            else addNoAvailable();
        }

        partial void OnSearchTextChanged(string value)
        {
            if (!updateTreeNodes(false)) addNoAvailable();
        }

        private bool updateTreeNodes(bool initializing)
        {
            var topNodes = new List<Node>();
            var itemAdded = false;
            var key = SearchText?.ToLower() ?? "";
            bool keyValid = key.Length >= 2;
            Node nodeToSelect = null;

            foreach (var top in fullTree)
            {
                var topMatch = keyValid && (top.ID.ToLower().Contains(key) || top.Name.ToLower().Contains(key));

                var topNode = new Node(top.ID, top.Name, false);
                var shouldAddTopNode = !keyValid || topMatch;
                var shouldExpand = false;

                var middleNodes = new List<Node>();
                foreach (var middle in top.Children)
                {
                    var middleMatch = keyValid && (middle.ID.ToLower().Contains(key) || middle.Name.ToLower().Contains(key));

                    var middleNode = new Node(middle.ID, middle.Name, false);
                    bool shouldAddMiddleNode = !keyValid || topMatch || middleMatch;

                    var bottomNodes = new List<Node>();
                    foreach (var bottom in middle.Children)
                    {
                        var bottomMatch = keyValid && (bottom.ID.ToLower().Contains(key) || bottom.Name.ToLower().Contains(key));
                        var isSelected = (int)bottom.Type >= (int)SignalTreeNodeType.GeneralSignal && originSignalID != null && bottom.ID == originSignalID;

                        var shouldAddBottomNode = !keyValid || topMatch || middleMatch || bottomMatch;
                        if (shouldAddBottomNode)
                        {
                            var bottomNode = new Node(bottom.ID, bottom.Name, true) { TextColor = isSelected ? TextColor.Green : TextColor.Blue };
                            if (isSelected)
                            {
                                nodeToSelect = bottomNode;
                                if (initializing) shouldExpand = true;
                            }
                            bottomNodes.Add(bottomNode);
                            shouldAddMiddleNode = true;
                        }
                    }

                    if (shouldAddMiddleNode)
                    {
                        foreach (var bottomNode in bottomNodes.OrderBy(node => node.Title))
                        {
                            middleNode.SubNodes.Add(bottomNode);
                        }
                        if (keyValid || shouldExpand) middleNode.IsExpanded = true;
                        middleNodes.Add(middleNode);
                        shouldAddTopNode = true;
                    }
                }

                if (shouldAddTopNode)
                {
                    foreach (var middleNode in middleNodes.OrderBy(node => node.Title))
                    {
                        topNode.SubNodes.Add(middleNode);
                    }
                    if (keyValid || shouldExpand) topNode.IsExpanded = true;
                    topNodes.Add(topNode);
                    itemAdded = true;
                }
            }

            TreeNodes.Clear();
            foreach (var topNode in topNodes.OrderBy(node => node.Title))
            {
                TreeNodes.Add(topNode);
            }

            SelectedTreeNode = nodeToSelect;
            return itemAdded;
        }

        private void addNoAvailable()
        {
            TreeNodes.Clear();
            TreeNodes.Add(new Node(null, language["no-available"], false) { TextColor = TextColor.Gray });
        }

        private SignalTreeNode[] fullTree;
    }
}